(function(window, angular, undefined) {'use strict';
	angular.module('kingServices', [])
    .factory('shallowCopy', function(){
        return function(obj){
            var key;
            var result;
            if(typeof obj === 'object' && obj !== null){
                result = (Object.prototype.toString.call(obj) === '[object Array]')
                   ? []
                   : {};
            }
            else {
                return obj;
            }
            
            for(key in obj){
                result[key] = obj[key]
            }
            return result;
        }
    })
    .factory('deepCopy', function(){
        function deepCopy(obj){
            var key;
            var result;
            if(typeof obj === 'object' && obj !== null){
                result = (Object.prototype.toString.call(obj) === '[object Array]')
                   ? []
                   : {};
            }
            else {
                return obj;
            }
            
            for (key in obj){
                result[key] = deepCopy(obj[key])
            }
            return result;
        }
        return deepCopy;
    })
    .factory('isEmptyObject', function(){
        return function(obj){
            var key;
            for(key in obj){
                if(obj.hasOwnProperty(key))
                   return false;
            }
            return true;
        }
    })
    .factory('orderBy', function(){
        return function o(arr, orderKey, compare, reverse){
            for (var i = 0; i < arr.length; i++) {
                arr[i].oldIndex = i;
            }
            return arr.sort(function(a, b){
                if(reverse){
                    var c 
                    c = a
                    a = b
                    b = c
                }
                return compare  
                    ? compare(a[orderKey], b[orderKey], orderKey, reverse)  
                        : a[orderKey] > b[orderKey] 
                            ? 1 
                            : a[orderKey] == b[orderKey] 
                                ? a.oldIndex - b.oldIndex
                                : -1
            })
        }
    })
    .factory('getDateSizeFromMonth', function(){
        return function(year, month){
            return (new Date(year, month+1, 0)).getDate()
        }
    })
    .factory('dateDataIniter', ['getDateSizeFromMonth', function(getDateSizeFromMonth){
        // 主要是生成日期，并计算日期与今日的关系
        function resetDates(y, m, current_year, current_month, current_date, callback){
            // createDate应写成构造器
            function createDate(d){
                var date = {}
                date.value = d
                if(y < current_year || (y == current_year && m < current_month))
                    date.available = true
                else if(y > current_year || (y == current_year && m > current_month))
                    date.available = false
                else 
                    date.available = i <= current_date
                return date
            }
            var i;
            if (!y) y = current_year
            if (!m && m !== 0) m = current_month
            var datesSize = getDateSizeFromMonth(y, m)
            var dates = [], date
            for (i = 1; i < datesSize + 1; ++i) {
                date = createDate(i)
                if(dates[i-1]){
                    dates[i-1].next = date
                    date.prev = dates[i-1]
                }
                typeof callback === 'function' && callback(date)
                dates.push(date)
            }
            dates[0].prev = null
            dates[dates.length - 1].next = null
            return dates
        }
        var dateDataIniter = function dateDataIniter(y, m, settings){
            var now = new Date()
            var current_year = now.getFullYear(),
                current_month = now.getMonth(),
                current_date = now.getDate()
            var callback = settings.callback
            var dates = resetDates(y, m, current_year, current_month, current_date, callback)
            
            var result = {}
            result.currentYear = current_year
            result.currentMonth = current_month
            result.currentDate = current_date
            result.dates = dates
            return result
        }
        return dateDataIniter
    }])
    .factory('extendCalendarSelect', ['isEmptyObject', function(isEmptyObject){
//      在翻页时需要检查当前日期里是否有已选日期
        return function(self, settings) {
            var getDateObj = settings.getDateObj,
                getYear = settings.getYear || function(){return self.showedYear},
                getMonth = settings.getMonth || function(){return self.showedMonth}
            
            self.selectedTime = self.selectedTime || {}
            self.selectDate = function(dateNum) {
                var showedYear = getYear.apply(this, arguments),
                    showedMonth = getMonth.apply(this, arguments)
                if(!this.selectedTime[showedYear])
                    this.selectedTime[showedYear] = {}
                var selectedYear = this.selectedTime[showedYear]
                if(!selectedYear[showedMonth])
                    selectedYear[showedMonth] = {}
                var selectedMonth = selectedYear[showedMonth]
                selectedMonth[dateNum] = true
                getDateObj.apply(null, arguments)['selected'] = true
            }
            self.unselectDate = function(dateNum) {
                delete getDateObj.apply(null, arguments).selected
                var showedYear = getYear.apply(this, arguments),
                    showedMonth = getMonth.apply(this, arguments)
                var selectedTime = this.selectedTime,
                    selectedYear = selectedTime[showedYear],
                    selectedMonth = selectedYear[showedMonth]
                delete selectedMonth[dateNum]
                if(isEmptyObject(selectedMonth)){
                    delete selectedYear[showedMonth]
                    if(isEmptyObject(selectedYear)){
                        delete selectedTime[showedYear]
                    }
                }
            }
            // 设定this.select 与 this.unselect。它们接受Number类型参数并调用this.selectDate、this.unselectDate
            var create = function(handler) {
                function mapDates(startNum, endNum, callback) {
                    if(startNum == null) {
                        startNum = self.dates[0].value
                    }
                    if(endNum == null) {
                        endNum = self.dates[self.dates.length - 1].value
                    }
                    var dateNum
                    for(dateNum = startNum; dateNum <= endNum; dateNum++) {
                        callback(dateNum)
                    }
                }

                return function(startNum, endNum) {
                    var args = arguments
                    var that = this
                    if($.isArray(startNum)) {
                        var dateNums = startNum
                        args = [].slice.call(args, 1)
                        $.each(dateNums, function(index, dateNum) {
                            handler.apply(that, [dateNum].concat(args))
                        })
                    } else if(arguments.length === 1 || typeof endNum !== 'number') {
                        var dateNum = startNum
                        handler.apply(that, [dateNum].concat(args))
                    } else {
                        mapDates(startNum, endNum, function(dateNum) {
                            handler.apply(that, [dateNum].concat(args))
                        })
                    }
                }
            }
            self.select = create(function(){
                return this.selectDate.apply(this, arguments)
            })
            self.unselect = create(function(){
                return this.unselectDate.apply(this, arguments)
            })
            self.unselectAll = function(){
                for(var year in this.selectedTime){
                    if(year == this.showedYear){
                        for(var month in this.selectedTime[year]){
                            if(month == this.showedMonth){
                                for(var date in this.selectedTime[year][month]){
                                    delete getDateObj(date).selected
                                }
                            }
                        }
                    }
                    delete this.selectedTime[year]
                }
            }
        }
    }])
    .factory('Calendar', ['dateDataIniter', 'extendCalendarSelect', function(dateDataIniter, extendCalendarSelect){
        return function Calendar(y, m, settings){
            
            if(!settings) settings = {}
            var self = this
            var now = new Date()
            
            if(arguments.length < 2){
                y = now.getFullYear()
                m = now.getMonth()
                settings = arguments[0] || {}
            }
            this.weekOrder = settings.weekOrder || 0
            this.dates = []
            var getShowedDate = this.getShowedDate = function (d){
                var date
                for(var i = 0, date;date = self.dates[i];i++){
                    if(date.value == d){
                        break
                    }
                }
                return date
            }
            this.initDates = function (){
                var self = this
                // 判断日期是否超出设定的范围
                // 应迁移到外部
                var setRange  = function(date){
                    function lt(a, b){
                        return a<b
                    }
                    function gt(a, b){
                        return a>b
                    }
                    var startDate = settings['startDate'], 
                        endDate = settings['endDate'],
                        outOfRangeCanBeAvailable = settings['outOfRangeCanBeAvailable']
                    var arr = [startDate, endDate], i = 0, range
                    for(;i<arr.length;++i){
                        range = arr[i]
                        if(!range) continue;
                        var type = i == 0 ? 'startDate' : 'endDate'
                        range = range.replace(/-/g, '.').split('.')
                        $.each(range, function(index, value){
                            range[index] = parseInt(value)
                        })
                        range[1]-- // 月份减一
                        var compare = type == 'startDate' ? lt : gt
                        if(
                            compare(self.showedYear, range[0]) || 
                            self.showedYear == range[0] && compare(self.showedMonth, range[1]) ||
                            self.showedYear == range[0] && self.showedMonth == range[1] && compare(date.value, range[2])
                        ){
                            date[type == 'startDate' ? 'front' : 'behind'] = true
                            if(!outOfRangeCanBeAvailable)
                                date.available = false
                        }
                    }
                }
                var datesData = dateDataIniter(this.showedYear, this.showedMonth, {
                    callback: function(date){
                        setRange(date)
                        settings.callback && settings.callback(date)
                    }
                })
                angular.forEach(['currentYear', 'currentMonth', 'currentDate'], function(value){
                    this[value] = datesData[value]
                }, this)
                this.dates.length = 0
                var i
                for(i in datesData.dates){
                    this.dates[i] = datesData.dates[i]
                }
                return this.dates
            }
            // 实现选择功能
            this.selectedTime = {}
            extendCalendarSelect(this, {getDateObj: getShowedDate})
            // 在翻页时需要检查当前日期里是否有已选日期
            this.setSelectedStatus = function(){
                var selectedYear = this.selectedTime[this.showedYear]
                if(selectedYear){
                    var selectedMonth = selectedYear[this.showedMonth]
                    if(selectedMonth){
                        for(var i = 0, date;date = this.dates[i];++i){
                            if(date.value in selectedMonth){
                                date.selected = true
                            }
                        }
                    }
                }
            }
            this.setCurrentDate = settings.setCurrentDate || function(year, month){
                if(this.currentYear === year && this.currentMonth === month){
                    var currentDate = getShowedDate(this.currentDate)
                    currentDate['isCurrent'] = true
                }
            }
            this.countIndent = settings.countIndent || function(year, month){
                var firstDay = (new Date(year, month, 1)).getDay(),
                    weekOrder = this.weekOrder
                
                var i
                if(firstDay >= weekOrder){
                    i = firstDay - weekOrder
                } else {
                    i = 7 + firstDay - weekOrder
                }
                for(;i>0;--i){
                    this.dates.unshift({
                        invalid: true,
                        value: null
                    })
                }
            }
            this.setYear = function(year){
                if(year === this.showedYear) return false;
                this.showedYear = year
                handle()
            }
            this.setMonth = function(month){
                if(month === this.showedMonth) return false;
                if(month < 0 || month > 11) {
                    year += Math.floor(month / 12)
                    month = (month < 0 ? 12 : 0) + month % 12
                    this.showedYear = year
                }
                this.showedMonth = month
                handle()
            }
            this.setTime = function(year, month){
                if(year === this.showedYear && month === this.showedMonth) return false;
                if(month < 0 || month > 11) {
                    year += Math.floor(month / 12)
                     month = (month < 0 ? 12 : 0) + month % 12
                }
                this.showedYear = year
                this.showedMonth = month
                handle()
            }
            
            // handle是在生成日历时调用的函数
            var handle = $.proxy(settings.handle || function(){
                var showedYear = this.showedYear, 
                    showedMonth = this.showedMonth
                var dates = this.initDates()
                this.setSelectedStatus()
                this.setCurrentDate(showedYear, showedMonth)
                this.countIndent(showedYear, showedMonth)
                settings.handleCallback && settings.handleCallback(dates)
                return dates
            }, this)
            this.setTime(y, m)
        }
    }])
})(window, window.angular);